package com.bsdsma.visonManagementSystemapp.restcontroller;

import com.bsdsma.visonManagementSystemapp.dto.ForgotPasswordDto;
import com.bsdsma.visonManagementSystemapp.dto.LoginParamDto;
import com.bsdsma.visonManagementSystemapp.dto.LoginUserDto;
import com.bsdsma.visonManagementSystemapp.dto.UserAddDto;
import com.bsdsma.visonManagementSystemapp.dto.UserDto;
import com.bsdsma.visonManagementSystemapp.entity.User;
import com.bsdsma.visonManagementSystemapp.entity.Student;
import com.bsdsma.visonManagementSystemapp.entity.Teacher;
import com.bsdsma.visonManagementSystemapp.entity.Admin;
import com.bsdsma.visonManagementSystemapp.service.SchoolService;
import com.bsdsma.visonManagementSystemapp.service.UserService;
import com.bsdsma.visonManagementSystemapp.constants.ErrorCodes;
import com.bsdsma.visonManagementSystemapp.constants.TokenConstants;
import com.bsdsma.visonManagementSystemapp.exceptionhandler.GlobalRuntimeException;
import com.bsdsma.visonManagementSystemapp.jwt.JwtUtils;
import com.bsdsma.visonManagementSystemapp.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping(value = "/api/auth")
public class AuthRestController {

    @Autowired
    private UserService userService;

    @Autowired
    private SchoolService schoolService;

    /**
     * 用户注册入口
     * @param param 注册参数 提交的内容结构为: {"nickname": "test", "password": "test_password"}
     * @return  返回的结构为: {"success": true, "msg", "注册成功"}
     */
    @PostMapping(value = "/register")
    public Map<String, Object> register(@RequestBody UserAddDto param){
        Map<String, Object> retMap = new HashMap<>(4);
        try{
            // 调用用户添加方法 把用户添加到数据库 如果没有发生异常 说明插入到数据库成功 这样我们就完成了注册
            userService.add(param, false);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            if(e instanceof GlobalRuntimeException){
                throw e;
            }
            throw new GlobalRuntimeException(ErrorCodes.UNKNOWN_ERROR, e.getMessage());
        }
        return ResultUtils.ok();
    }

    @PostMapping(value = "/logout")
    public Map<String, Object> logout(HttpServletRequest request){
        Long uid = (Long) request.getAttribute(TokenConstants.UID);
        RedisMockUtils.getUserToken(uid);
        return ResultUtils.ok();
    }

    @PostMapping(value = "/noauth/forgot-passowrd")
    public Map<String, Object> forgotPassword(@RequestBody ForgotPasswordDto param){
        String account = param.getAccount();
        String cellphoneNumber = param.getCellphoneNumber();
        String password = param.getPassword();
        // 校验空字段
        if(StringUtils.isBlank(account)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入账号");
        }
        if(StringUtils.isBlank(cellphoneNumber)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入手机号");
        }
        if(StringUtils.isBlank(password)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入新密码");
        }
        // 通过账号查询用户表
        UserDto userDto = userService.getByAccount(account);
        if(null == userDto){
            // 说明数据库中不存在这个账号
            throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "该账号不存在");
        }
        String cellPhoneNumberInDb = userDto.getCellphoneNumber();
        if(StringUtils.isBlank(cellPhoneNumberInDb)){
            throw new GlobalRuntimeException(ErrorCodes.UNKNOWN_ERROR, "该账号未录入手机号，无法找回密码，请联系管理员");
        }
        if(!cellPhoneNumberInDb.equals(cellphoneNumber)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "信息不正确");
        }

        // Check if new password is same as old password
        if(userDto.getPassword().equals(password)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "新密码与旧密码相同");
        }

        // Create a UserAddDto for the update
        UserAddDto updateDto = new UserAddDto();
        updateDto.setAccount(userDto.getAccount());
        updateDto.setPassword(password); // Use the new password
        updateDto.setName(userDto.getName());
        updateDto.setCellphoneNumber(userDto.getCellphoneNumber());
        updateDto.setRole(userDto.getRole());
        
        // Set role-specific fields based on the user's role
        updateDto.setXuexiao(userDto.getXuexiao());
        updateDto.setNianji(userDto.getNianji());
        updateDto.setBanji(userDto.getBanji());
        updateDto.setXuehao(userDto.getXuehao());
        
        // Update the user using the update method
        userService.update(userDto.getId(), updateDto);
        return ResultUtils.ok();
    }

    private <T extends User> void updateUserFromDto(T user, UserDto dto) {
        user.setId(dto.getId());
        user.setAccount(dto.getAccount());
        user.setPassword(dto.getPassword());
        user.setName(dto.getName());
        user.setCellphoneNumber(dto.getCellphoneNumber());
        user.setHeadImgKey(dto.getHeadImgKey());
        user.setStatus(dto.getStatus());
        user.setCt(dto.getCt());
        user.setUt(dto.getUt());

        if (user instanceof Student) {
            Student student = (Student) user;
            student.setXuexiaoId(schoolService.findByName(dto.getXuexiao()).getId());
            student.setNianji(dto.getNianji() != null ? Student.Grade.fromDisplayName(dto.getNianji()) : null);
            student.setBanji(dto.getBanji());
            student.setXuehao(dto.getXuehao());
        } else if (user instanceof Teacher) {
            Teacher teacher = (Teacher) user;
            teacher.setXuexiaoId(schoolService.findByName(dto.getXuexiao()).getId());
            teacher.setGonghao(dto.getGonghao());
        } else if (user instanceof Admin) {
            Admin admin = (Admin) user;
            admin.setGonghao(dto.getGonghao());
        }
    }

    /**
     * 用户登录入口
     * @param param 登录参数
     * @return
     */
    @PostMapping(value = "/login")
    public Map<String, Object> login(@RequestBody LoginParamDto param){
        Map<String, Object> retMap = new HashMap<>(4);
        // 代表是否成功 true则表示注册成功 false则表示注册失败
        String account = param.getAccount();
        String password = param.getPassword();
        // 先校验传入的账号/密码是否是空白字符串 给出相应提示
        if(StringUtils.isBlank(account)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入账号");
        }
        if(StringUtils.isBlank(password)){
            throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "请输入密码");
        }
        try{
            // 通过账号查询用户表
            UserDto loginUser = userService.getByAccount(account);
            if(null == loginUser){
                // 说明数据库中不存在这个账号
                throw new GlobalRuntimeException(ErrorCodes.OBJ_NOT_EXISTS, "该账号不存在");
            }
            // 获取该用户真实的密码
            String realPassword = loginUser.getPassword();
            // 判断真实密码和用户输入的密码是否是不一致的
            if(!realPassword.equals(password)){
                // 密码不一致
                throw new GlobalRuntimeException(ErrorCodes.PARAMS_ERROR, "账号/密码错误");
            }
            // 既然密码一致了，那就是登录成功了 生成登录用户token
            String token = JwtUtils.create(loginUser.getId());
            // 1.token要在服务端存起来，用于比对客户端请求带过来的token是否是正确的
            RedisMockUtils.putUserToken(loginUser.getId(), token);
            // Convert UserDto to the correct User subclass
            User userEntity;
            switch (loginUser.getRole()) {
                case "学生":
                    userEntity = new Student();
                    break;
                case "教师":
                    userEntity = new Teacher();
                    break;
                case "超级管理员":
                    userEntity = new Admin();
                    break;
                default:
                    throw new GlobalRuntimeException(ErrorCodes.PERMISSION_ERROR, "无效的用户角色");
            }
            updateUserFromDto(userEntity, loginUser);
            RedisMockUtils.putUser(loginUser.getId(), userEntity);
            // 2.把token返回给客户端，客户端将token持久化起来，
            retMap.put("token", token);
            retMap.put("user", CustomerBeanUtils.copyPropertiesClass(loginUser, LoginUserDto.class));
            return ResultUtils.ok(retMap);
            // 3.之后的请求客户端都需要带着token访问
        }catch (Exception e){
            throw new GlobalRuntimeException(ErrorCodes.UNKNOWN_ERROR, e.getMessage());
        }
    }
}
